{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Functions是python中很重要的概念。可以用def来定义："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def my_function(x, y, z=1.5):\n",
    "    if z > 1:\n",
    "        return z * (x + y)\n",
    "    else:\n",
    "        return z / (x + y)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "上面可以return多个结果，如果没有return语句的话，默认会返回None。\n",
    "\n",
    "每个function有positional arguments（位置参数） and keyword arguments（关键字参数）。keyword argument通常用来指定默认的值或可选参数。在上面的函数里，x和y是位置参数，而z是一个关键字参数。我们可以通过下面的方式调用："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.06363636363636363"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "my_function(5, 6, z=0.7)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "35.49"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "my_function(3.14, 7, 3.5)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "45.0"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "my_function(10, 20)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "一个需要强制遵守的规则是，函数的参数顺序为，位置参数在前，关键字参数在后。而多个关键字参数的位置是可以自己指定的。比如下面的x，y，z都是关键字参数，调用函数的时候没有按顺序也可以："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "my_function(x=5, y=6, z=7)\n",
    "my_function(y=6, x=5, z=7)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 1 Namespaces, Scope, and Local Functions（命名空间，作用范围，局部函数）\n",
    "\n",
    "scope分两种，global and local （全局和局部）。namespace用来描述变量的作用范围。当调用一个函数的时候，会自动创建一个局部命名空间，用来存放函数的参数，一旦函数结束，局部命名空间会被自动废弃掉。考虑下面的例子："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def func():\n",
    "    a = []\n",
    "    for i in range(5):\n",
    "        a.append(i)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "当func()被调用，会创建一个空list a，然后5个元素赋给a。函数结束后，a也会被废弃。假设有下面的定义："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "a = []\n",
    "def func():\n",
    "    for i in range(5):\n",
    "        a.append(i)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "给函数范围外的变量赋值是可行的，但是这些变量必须通过global关键字来声明："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "a = None\n",
    "\n",
    "def bind_a_variable():\n",
    "    global a\n",
    "    a = []\n",
    "\n",
    "bind_a_variable()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[]"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这里我们不推荐使用global关键字。因为这个全局变量通常用于存储系统状态（state in a system)，如果你用了很多全局变量，或许你该考虑使用class。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 2 Returning Multiple Values（返回多个值）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def f():\n",
    "    a = 5\n",
    "    b = 6\n",
    "    c = 7\n",
    "    return a, b, c\n",
    "\n",
    "a, b, c = f()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "原理：其实函数还是返回了一个object，即tuple，然后这个tuple被解压给了result variables. 比如：\n",
    "\n",
    "    return_value = f()\n",
    "    \n",
    "这样的话，return_value就是一个3-tuple。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 3 Functions Are Objects（函数是对象）\n",
    "\n",
    "因为函数时对象，所以很多构造能轻易表达出来。比如我们要对下面的string做一些数据清洗："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "states = [' Alabama ', 'Georgia!', 'Georgia', 'georgia', \n",
    "          'FlOrIda', 'south carolina##', 'West virginia?']"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "要想让这些string统一，我们要做几件事：去除空格，删去标点符号，标准化大小写。一种做法是利用内建函数和re模块（正则表达式）："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import re\n",
    "\n",
    "def clean_string(strings):\n",
    "    result = []\n",
    "    for value in strings:\n",
    "        value = value.strip()\n",
    "        value = re.sub('[!#?]', '', value)\n",
    "        value = value.title()\n",
    "        result.append(value)\n",
    "    return result"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['Alabama',\n",
       " 'Georgia',\n",
       " 'Georgia',\n",
       " 'Georgia',\n",
       " 'Florida',\n",
       " 'South Carolina',\n",
       " 'West Virginia']"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "clean_string(states)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "还有一种做法，把一系列操作放在一个list里："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def remove_punctuation(value):\n",
    "    return re.sub('[!#?]', '', value)\n",
    "\n",
    "clean_ops = [str.strip, remove_punctuation, str.title]\n",
    "\n",
    "def clean_strings(strings, ops):\n",
    "    result = []\n",
    "    for value in strings:\n",
    "        for function in ops:\n",
    "            value = function(value)\n",
    "        result.append(value)\n",
    "    return result"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['Alabama',\n",
       " 'Georgia',\n",
       " 'Georgia',\n",
       " 'Georgia',\n",
       " 'Florida',\n",
       " 'South Carolina',\n",
       " 'West Virginia']"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "clean_strings(states, clean_ops)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "一个更函数化的方式能让你方便得在一个高等级上转变string。可以把函数当做其他函数的参数，比如用内建的map函数，这个map函数能把一个函数用于一个序列上："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " Alabama \n",
      "Georgia\n",
      "Georgia\n",
      "georgia\n",
      "FlOrIda\n",
      "south carolina\n",
      "West virginia\n"
     ]
    }
   ],
   "source": [
    "for x in map(remove_punctuation, states):\n",
    "    print(x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 4 Anonymous (Lambda) Functions(匿名函数，lambda函数)\n",
    "\n",
    "这种函数只有一行，结果能返回值。下面两个函数是一样的效果："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def short_function(x):\n",
    "    return x * 2\n",
    "\n",
    "equiv_anon = lambda x: x * 2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "之后我们只称其为lambda函数。这种函数在数据分析方面非常有用，就因为方便。比如下面的例子："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[8, 0, 2, 10, 12]"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def apply_to_list(some_list, f):\n",
    "    return [f(x) for x in some_list]\n",
    "\n",
    "ints = [4, 0, 1, 5, 6]\n",
    "apply_to_list(ints, lambda x: x * 2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "假设你想按不同字母的数量给一组string排序："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "strings = ['foo', 'card', 'bar', 'aaaa', 'abab']\n",
    "\n",
    "strings.sort(key=lambda x: len(set(list(x))))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['aaaa', 'foo', 'abab', 'bar', 'card']"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "strings"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 5 Currying: Partial Argument Application(柯里化：局部参数应用)\n",
    "\n",
    "在计算机科学中，柯里化（Currying）是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数，并且返回接受余下的参数且返回结果的新函数的技术。\n",
    "\n",
    "[函数加里化是一种实现多参数函数的方法。](http://www.vaikan.com/currying-partial-application/)\n",
    "\n",
    "简单的说，通过局部参数应用，在一个原有函数的基础上，构造一个新的函数。比如，我们想要一个加法的函数：\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def add_number(x, y):\n",
    "    return x + y"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "通过上面这个函数，我们可以衍生出一个只需要一个参数的新方程，add_five，即把5加到参数上："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "add_five = lambda y: add_number(5, y)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "其中第二个参数y叫做被柯里化了。这其实没什么特别的，我们做的其实就是用一个已有的函数定义了一个新函数。而内建的functools模块里的partial函数能简化这个操作："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "from functools import partial\n",
    "add_five = partial(add_number, 5)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 6 Generators(生成器)\n",
    "\n",
    "这个东西在python里很重要，能用来迭代序列。比如，迭代一个字典："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "a\n",
      "b\n",
      "c\n"
     ]
    }
   ],
   "source": [
    "some_dict = {'a': 1, 'b': 2, 'c': 3}\n",
    "\n",
    "for key in some_dict:\n",
    "    print(key)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "当我们写`for key in some_dict`的时候，python解释器就新建了一个iterator："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "dict_iterator = iter(some_dict)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<dict_keyiterator at 0x104c92ef8>"
      ]
     },
     "execution_count": 30,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "dict_iterator"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "一个生成器能产生object给python 解释器，当遇到for loop这样的情景时。大部分方法，除了list之类的object，都能接受迭代器。比如内建的函数min, max, sum,或是类型构造器 list, tuple:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['a', 'b', 'c']"
      ]
     },
     "execution_count": 31,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "list(dict_iterator)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "生成器是用于构造迭代对象的简洁方式。不像其他函数一口气执行完，返回一个结果，生成器是多次返回一个序列，每请求一次，才会返回一个。用yield可以构建一个生成器："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def squares(n=10):\n",
    "    print('Generating squares from 1 to {0}'.format(n**2))\n",
    "    for i in range(1, n+1):\n",
    "        yield i ** 2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "当你实际调用一个生成器的时候，不会有代码立刻执行："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<generator object squares at 0x104c95bf8>"
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "gen = squares()\n",
    "gen"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "知道我们发出请求，生成器才会执行代码："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Generating squares from 1 to 100\n",
      "1 4 9 16 25 36 49 64 81 100 "
     ]
    }
   ],
   "source": [
    "for x in gen:\n",
    "    print(x, end=' ')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Generator expresssions (生成器表达式)\n",
    "另一个构造生成器的方式是利用生成器表达式。写法就像列表表达式一样，只不过使用括号："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "gen = (x ** 2 for x in range(100))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<generator object <genexpr> at 0x1049d9c50>"
      ]
     },
     "execution_count": 36,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "gen"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "上面的代码和下面冗长的代码是等效的："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def _make_gen():\n",
    "    for x in range(100):\n",
    "        yield x ** 2\n",
    "gen = _make_gen()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "生成器表达式还能作为函数的参数，而列表表达式不能作为函数的参数："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "328350"
      ]
     },
     "execution_count": 38,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "sum( x ** 2 for x in range(100))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{0: 0, 1: 1, 2: 4, 3: 9, 4: 16}"
      ]
     },
     "execution_count": 39,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "dict((i, i**2) for i in range(5))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## itertools module\n",
    "\n",
    "itertools模块有很多常用算法的生成器。比如groupby能取任意序列当做函数，"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import itertools \n",
    "\n",
    "first_letter = lambda x: x[0]\n",
    "names = ['Alan', 'Adam', 'Wes', 'Will', 'Albert', 'Steven']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "A ['Alan', 'Adam']\n",
      "W ['Wes', 'Will']\n",
      "A ['Albert']\n",
      "S ['Steven']\n"
     ]
    }
   ],
   "source": [
    "for letter, group in itertools.groupby(names, first_letter):\n",
    "    print(letter, list(group)) # names is a generator"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "看的不是很懂，去找资料看了看解释。\n",
    "\n",
    "> itertools.groupby(iterable[, key])\n",
    "返回一个产生按照key进行分组后的值集合的迭代器.\n",
    "\n",
    "> 如果iterable在多次连续迭代中生成了同一项，则会定义一个组，如果将此函数应用一个分类列表，那么分组将定义该列表中的所有唯一项，key（如果已提供）是一个函数，应用于每一项，如果此函数存在返回值，该值将用于后续项而不是该项本身进行比较，此函数返回的迭代器生成元素(key, group)，其中key是分组的键值，group是迭代器，生成组成该组的所有项。\n",
    "\n",
    "> 即：按照keyfunc函数对序列每个元素执行后的结果分组(每个分组是一个迭代器), 返回这些分组的迭代器\n",
    "\n",
    "按我的理解，`itertools.groupby(names, first_letter)`，把names中的每个没穿放入到first_letter这个函数中，得到了首字母作为key，赋给了letter。但后面那个group的结果我没看懂，Albert也是A开头的，为什么没有归到第一组里呢？\n",
    "\n",
    "一些迭代工具函数：\n",
    "![](../MarkdownPhotos/chp03/屏幕快照 2017-10-25 下午2.04.40.png)\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 7 Errors and Exception Handling（错误和异常处理）\n",
    "\n",
    "在数据分析应用中，许多函数只能用于特定的输入。比如float能把strign变为浮点数，但如果有不正确的输入的话会报错："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1.2345"
      ]
     },
     "execution_count": 46,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "float('1.2345')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "ename": "ValueError",
     "evalue": "could not convert string to float: 'something'",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mValueError\u001b[0m                                Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-47-439904410854>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mfloat\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'something'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;31mValueError\u001b[0m: could not convert string to float: 'something'"
     ]
    }
   ],
   "source": [
    "float('something')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "假设我们想要这个float失败的优雅一些，返回输入的参数。我们可以用try/except："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def attempt_float(x):\n",
    "    try:\n",
    "        return float(x)\n",
    "    except:\n",
    "        return x"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这个except的部分只有当float(x)引发异常的时候才会执行："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1.2345"
      ]
     },
     "execution_count": 51,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "attempt_float('1.2345')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'something'"
      ]
     },
     "execution_count": 52,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "attempt_float('something')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "当然，float也可能引发除了ValueError之外的异常："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "ename": "TypeError",
     "evalue": "float() argument must be a string or a number, not 'tuple'",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-53-842079ebb635>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mfloat\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m2\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;31mTypeError\u001b[0m: float() argument must be a string or a number, not 'tuple'"
     ]
    }
   ],
   "source": [
    "float((1, 2))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "你可能只想控制ValueError，因为如果是TypeError的话，错误提示对你debug是有帮助的："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def attempt_float(x):\n",
    "    try:\n",
    "        return float(x)\n",
    "    except ValueError:\n",
    "        return x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "ename": "TypeError",
     "evalue": "float() argument must be a string or a number, not 'tuple'",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-55-9bdfd730cead>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mattempt_float\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m2\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;32m<ipython-input-54-84efde0a7059>\u001b[0m in \u001b[0;36mattempt_float\u001b[0;34m(x)\u001b[0m\n\u001b[1;32m      1\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mattempt_float\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      2\u001b[0m     \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m         \u001b[0;32mreturn\u001b[0m \u001b[0mfloat\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m      4\u001b[0m     \u001b[0;32mexcept\u001b[0m \u001b[0mValueError\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      5\u001b[0m         \u001b[0;32mreturn\u001b[0m \u001b[0mx\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mTypeError\u001b[0m: float() argument must be a string or a number, not 'tuple'"
     ]
    }
   ],
   "source": [
    "attempt_float((1, 2))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "当然，你也可以捕捉多个不同的异常："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def attempt_float(x):\n",
    "    try:\n",
    "        return float(x)\n",
    "    except (TypeError, ValueError):\n",
    "        return x"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在某些情况下，你不想抑制任何异常，但你想希望执行某些代码，不论try里的代码成功执行与否。这样的话，需要用的finally:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "f = open(path, 'w')\n",
    "\n",
    "try:\n",
    "    write_to_file(y)\n",
    "finally:\n",
    "    f.close()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这样的处理会始终会让f关闭。同样的，你可以在try里的代码成功执行后，让某些代码执行："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "f = open(path, 'w')\n",
    "\n",
    "try:\n",
    "    write_to_file(f)\n",
    "except:\n",
    "    print('Failed')\n",
    "else:\n",
    "    print('Succeeded')\n",
    "finally:\n",
    "    f.close()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Exceptions in IPython (IPython中的异常)\n",
    "\n",
    "当使用%run执行代码片段，引发异常后，IPython中默认打印出所有的调用信息（traceback）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "ERROR:root:File `'example/ipython_bug.py'` not found.\n"
     ]
    }
   ],
   "source": [
    "%run example/ipython_bug.py"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python [py35]",
   "language": "python",
   "name": "Python [py35]"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.5.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
